package cn.zzdt4j.config.springboot.starter.refresher;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.cloud.bootstrap.config.BootstrapPropertySource;
import org.springframework.cloud.consul.config.ConsulPropertySource;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.env.AbstractEnvironment;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * Consul refresher handler
 *
 * @author by <a href="mailto:ligang941012@gmail.com">gang.Li</a>
 * @since 2024/5/13 2:17
 */
@Slf4j
public class ConsulRefresherHandler extends AbstractConfigThreadPoolDynamicRefresh {
    private static final int INITIAL_CAPACITY = 64;

    @EventListener(EnvironmentChangeEvent.class)
    public void refreshed(EnvironmentChangeEvent event) {
        dynamicRefresh(StrUtil.EMPTY, extractLatestConfigInfo(event));
    }

    private Map<String, Object> extractLatestConfigInfo(EnvironmentChangeEvent event) {
        AbstractEnvironment environment = (AbstractEnvironment) ((AnnotationConfigServletWebServerApplicationContext) event.getSource()).getEnvironment();

        final String activeProfile = Optional.ofNullable(environment.getActiveProfiles().length > 0 ? environment.getActiveProfiles()[0] : null)
                .orElseGet(() -> String.valueOf(getApplicationConfigDefaultContext(environment)));
        final List<BootstrapPropertySource<?>> bootstrapPropertySourceList = environment.getPropertySources().stream()
                .filter(propertySource -> propertySource instanceof BootstrapPropertySource)
                .map(propertySource -> (BootstrapPropertySource<?>) propertySource).collect(Collectors.toList());
        final Optional<BootstrapPropertySource<?>> bootstrapPropertySource = bootstrapPropertySourceList.stream()
                .filter(source -> source.getName().contains(activeProfile) && source.getPropertyNames().length != 0).findFirst();
        final Map<String, Object> configInfo = new HashMap<>(INITIAL_CAPACITY);
        if (bootstrapPropertySource.isPresent()) {
            final ConsulPropertySource consulPropertySource = (ConsulPropertySource) bootstrapPropertySource.get().getDelegate();
            String[] propertyNames = consulPropertySource.getPropertyNames();
            for (String propertyName : propertyNames) {
                configInfo.put(propertyName, consulPropertySource.getProperty(propertyName));
            }
        }
        return configInfo;
    }

    @SuppressWarnings("unchecked")
    private CharSequence getApplicationConfigDefaultContext(AbstractEnvironment environment) {
        return environment.getPropertySources().stream()
                .filter(propertySource -> propertySource instanceof OriginTrackedMapPropertySource)
                .map(propertySource -> ((Map<String, CharSequence>) propertySource.getSource()).get("spring.cloud.consul.config.default-context"))
                .findFirst().orElse(StrUtil.EMPTY);
    }

    @Override
    public void registerListener() {
        // The listener has been registered by annotation.
    }
}
